require 'MeCab'

#Functionクラス
class Function
  attr_reader :str_array, :ex_array
  def initialize(opt = '')
    @mecab = MeCab::Tagger.new(opt)
  end

  #文字列sの形態素解析の結果を改行でスプリットして@str_arrayに格納
  def morph(s = '')
    @str_array = []
    @mecab.parse(s).split("\n").each{|elm|
      @str_array.push elm
    }
  end

  #ファイルfの中身をタブでスプリットして@ex_arrayに格納
  def crawl(f)
    @ex_array = []
    File.open(f){|io|
      while line = io.gets
        next if line =~ /^(\s*$|#)/
        @ex_array.push line.chomp.split("\t")
      end
    }
    @ex_array.sort!{|a, b| a[0].to_i <=> b[0].to_i}
  end

  #within_ex：文型の語の切れ目を探す関数
  #seqは文型を一文字単位でスプリットしたもの　配列
  #strは例文候補をmecabで解析したもの　配列
  def within_ex(str, seq)
    return true if seq == []
    return false if str == ["EOS"]

    wd = str.shift
    wdset = wd.split(/(,|\t)/)
    s = seq.shift
    if s[0] =~ /\*/ then
      if s[1] =~ /\*/ then
        return seek_ex(str, seq)
      else
        return within_ex(str, seq)
      end
    else
        if wdset[0] == s[0] && wdset[2] == s[1].chomp then
        result = within_ex(str.dup, seq.dup) 
        return result
      end
    end
    return false
  end

  #seek_ex：文型の文字を例文候補から探す関数
  #seqは文型を一文字単位でスプリットしたもの　配列
  #strは例文候補をmecabで解析したもの　配列
  def seek_ex(str, seq)
    return true if seq == []
    return false if str == ["EOS"]

    s = seq.shift
    if s[0] =~ /\*/ then
      if s[1] =~ /\*/ then
        str.shift
        result = seek_ex(str, seq)
        return result if result
      else
        while wd = str.shift
          wdset = wd.split(/(,|\t)/)
          if wdset[2] == s[1] then
            result = within_ex(str.dup, seq.dup)
            return result if result
          end
        end
      end
    else
      while wd = str.shift
        wdset = wd.split(/(,|\t)/)
        if wdset[0] == s[0] && wdset[2] == s[1].chomp then
          result = within_ex(str.dup, seq.dup)
          return result if result
        end
      end
    end

    return false
  end

  #データをパーズして配列に格納する
  def seq_array(bunkei)
    buf = []
    bunkei.scan(/\[(.*?)\]/){ buf.push $1.split(/,\s*/) }
    return buf
  end

  #実行
  def run(s = nil)
    self.morph(s) if s
    @ex_array.each{|ex|
      kyu, hoge, bunkei = ex
      next if bunkei =~ /UNKNOWN/
      seq = seq_array(bunkei)
      if seek_ex(@str_array.dup, seq.dup) then
#        p seq
        return kyu 
      end
    }
    return 9
  end  
end
